package com.zp.datax.core.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zp.datax.core.function.BiConsumerWrapper;
import com.zp.datax.core.function.BiFunctionWrapper;
import lombok.Cleanup;
import lombok.SneakyThrows;

import java.io.*;

/**
 * Jackson util
 * <p>
 * 1、obj need private and set/get；
 * 2、do not support inner class；
 *
 * @author xuxueli 2015-9-25 18:02:56
 */
public class JacksonUtil {
    private final static ObjectMapper objectMapper = new ObjectMapper();

    public static ObjectMapper getInstance() {
        return objectMapper;
    }

    /**
     * bean、array、List、Map --> json
     *
     * @param obj
     * @return json string
     * @throws Exception
     */
    @SneakyThrows
    public static String writeValueAsString(Object obj) {
        return getInstance().writeValueAsString(obj);
    }

    /**
     * string --> bean、Map、List(array)
     *
     * @param jsonStr
     * @param clazz
     * @return obj
     * @throws Exception
     */
    @SneakyThrows
    public static <T> T readValue(String jsonStr, Class<T> clazz) {
        return getInstance().readValue(jsonStr, clazz);
    }

    /**
     * string --> List<Bean>...
     *
     * @param jsonStr
     * @param parametrized
     * @param parameterClasses
     * @param <T>
     * @return
     */
    @SneakyThrows
    public static <T> T readValue(String jsonStr, Class<?> parametrized, Class<?>... parameterClasses) {
        JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses);
        return getInstance().readValue(jsonStr, javaType);
    }

    /**
     * file --> List<Bean>...
     *
     * @param reader
     * @param parametrized
     * @param parameterClasses
     * @param <T>
     * @return
     */
    @SneakyThrows
    public static <T> T readValue(Reader reader, Class<?> parametrized, Class<?>... parameterClasses) {
        JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses);
        return getInstance().readValue(reader, javaType);
    }

    @SneakyThrows
    public static <T> T readValue(Reader reader, Class<T> valueType) {
        return getInstance().readValue(reader, valueType);
    }

    @SneakyThrows
    public static <T> T readValue(BiFunctionWrapper<Reader, Class<T>, T, Exception> function, File file, Class<T> valueType) {
        @Cleanup
        FileReader fileReader = new FileReader(file);
        @Cleanup
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        return function.apply(bufferedReader, valueType);
    }

    public static <T> T readValue(File file, Class<T> valueType) {
        return readValue((r, v) -> readValue(r, v), file, valueType);
    }

    @SneakyThrows
    public static <T> T readValue(File file, TypeReference valueTypeRef) {
        return getInstance().readValue(file, valueTypeRef);
    }

    @SneakyThrows
    public static void writeValue(BiConsumerWrapper<Writer, Object, Exception> consumer, File file, Object value) {
        @Cleanup
        Writer writer = new FileWriter(file);
        @Cleanup
        BufferedWriter bufferedWriter = new BufferedWriter(writer);

        consumer.accept(bufferedWriter, value);

    }

    public static void writeValue(File file, Object value) {
        writeValue((w, v) -> writeValue(w, v), file, value);
    }

    public static void writeValue(String pathname, Object value) {
        writeValue((w, v) -> writeValue(w, v), new File(pathname), value);
    }

    /**
     * @param writer
     * @param value
     */
    @SneakyThrows
    public static void writeValue(Writer writer, Object value) {
        getInstance().writerWithDefaultPrettyPrinter().writeValue(writer, value);
    }

}
